package com.tony.juc;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created with IntelliJ IDEA.
 *
 * @Title: ReadWriteLockDemo001
 * @Auther: 皮蛋布丁
 * @Date: 2022/04/09/19:42
 * @Description: 读写锁
 */
public class ReadWriteLockDemo001 {

    public static void main(String[] args) {
        ReadWriteLockAccount account = new ReadWriteLockAccount("皮蛋布丁",0);//定义银行账户信息
        int money[] = new int[] {11000,23000,100_000}; //定义要存款的金额
        for (int i = 0; i < 10; i++) {
            if (i % 2 == 0) {
                new Thread(()->{
                    for (int j = 0; j < money.length; j++) {
                        account.save(money[j]); //存款操作
                    }
                },"存款线程_" + i).start();
            } else {
                new Thread(()->{
                    while (true) {
                        System.out.println(account);
                    }
                },"取款线程_" + i).start();
            }
        }

    }
}

class ReadWriteLockAccount {
    private String name; //账户名称
    //大厂都不会使用double描述金额，因为会有一个浮点的进位的bug，出现金额漏洞
    private int asset; //账户的资金，资金使用整型
    //因为读不需要考虑到线程同步处理，但是写需要考虑到线程同步处理
    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock() ;//读写锁

    public ReadWriteLockAccount(String name, int asset) {
        this.name = name;
        this.asset = asset;
    }

    public void save(int asset) { //向银行账户中进行存款操作
        this.readWriteLock.writeLock().lock();//写入锁定
        try {
            this.asset += asset;//存款处理
            TimeUnit.SECONDS.sleep(1);//模拟业务的处理延迟
            System.err.printf("【%s】修改银行资产，当前的资产为：%10.2f%n",Thread.currentThread().getName(),this.asset/100.0);
        } catch (Exception e) {}
        finally {
            this.readWriteLock.writeLock().unlock();//解除锁定
        }
    }

    @Override
    public String toString() {
        this.readWriteLock.readLock().lock();//读锁属于共享锁
        try {
            TimeUnit.MILLISECONDS.sleep(200);//模拟业务延迟
            return String.format("【%s】账户名称：%s、账户余额：%10.2f%n",Thread.currentThread().getName(),this.name,
                    this.asset/100.0);
        } catch (Exception e) {
            return null;
        }
        finally {
            this.readWriteLock.readLock().unlock();//解除锁定
        }

    }
}
